home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / misc / moonbas2 / vga_y.cpp < prev    next >
C/C++ Source or Header  |  1995-04-11  |  15KB  |  587 lines

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <conio.h>
  4. #include <dos.h>
  5.  
  6. #include "boolean.h"
  7. #include "vga.h"
  8.  
  9. //#define VSYNC_MONITOR  // This puts a bar graph on the screen that shows
  10.                        // how much time is being spent waiting for
  11.                        // vertical retrace.
  12.  
  13. char * const       screen_lin_addr = (char *) 0xA0000;
  14.  
  15. const              video_int       = 0x10;   // Video interrupt number
  16. const              sequ_addr       = 0x3c4;  // Base port of Sequencer
  17. const              crtc_addr       = 0x3d4;  // Base port of CRT Controller
  18. const              input_status_1  = 0x3da;  // Input Status 1 register
  19.  
  20. const              screen_width    = 320;
  21. const              screen_height   = 200;
  22. const              bytes_per_row   = 80;
  23.  
  24. //----------------------------------------------------------------------------
  25.  
  26. // These values contain the high byte of the page's offset in display memory,
  27. // along with the byte 0x0C, which indicates to the CRT Controller that we
  28. // are setting the high byte of the display offset.
  29. //
  30. // Note that the low byte of the display page is not changed.
  31.  
  32. static int         v_page_nr = 0x000C;
  33. static int         a_page_nr = 0x3f0C;
  34.  
  35. // The addresses of the active and visible screen pages.
  36.  
  37.        char *      v_page    = screen_lin_addr + 0x0000;
  38.        char *      a_page    = screen_lin_addr + 0x3f00;
  39.  
  40. // The saved screen mode number.
  41.  
  42. static int         old_mode_nr;
  43.  
  44. // Edge arrays.
  45.  
  46. static int         edge_l [ screen_height ];
  47. static int         edge_r [ screen_height ];
  48.  
  49. //----------------------------------------------------------------------------
  50. // The VGA object.  (Only one is allowed.)
  51. //----------------------------------------------------------------------------
  52.  
  53. vga_t              vga;
  54.  
  55. //----------------------------------------------------------------------------
  56. // FUNCTION  swap
  57. //----------------------------------------------------------------------------
  58.  
  59. inline void        swap
  60. (
  61.    int&            var1,
  62.    int&            var2
  63. )
  64. {
  65.    int             temp;
  66.  
  67.    temp  =  var1;
  68.    var1  =  var2;
  69.    var2  =  temp;
  70. }
  71.  
  72. //----------------------------------------------------------------------------
  73. // FUNCTION  draw_scanlines
  74. //----------------------------------------------------------------------------
  75. // Draws the scan lines from y1 to y2, using the X coordinates stored in the
  76. // edge_l and edge_r arrays.
  77. //----------------------------------------------------------------------------
  78.  
  79. static int         l_clip_plane_mask [] = { 0x0F02, 0x0E02, 0x0C02, 0x0802 };
  80. static int         r_clip_plane_mask [] = { 0x0102, 0x0302, 0x0702, 0x0F02 };
  81.  
  82. inline void        draw_scanlines
  83. (
  84.    int             y1,
  85.    int             y2,
  86.    int             color
  87. )
  88. {
  89.    char *          row_addr = a_page + (y1 * bytes_per_row);
  90.  
  91.    for ( int i = y1; i <= y2; ++ i )
  92.    {
  93.       int x1 = edge_l [i];
  94.       int x2 = edge_r [i];
  95.  
  96.       if ( x2 < x1 )
  97.       {
  98.          continue;
  99.       }
  100.  
  101.       char * first_byte_addr = row_addr + x1 / 4;
  102.       char * last_byte_addr  = row_addr + x2 / 4;
  103.  
  104.       int l_clip = l_clip_plane_mask [x1 & 3];
  105.       int r_clip = r_clip_plane_mask [x2 & 3];
  106.  
  107.       if ( first_byte_addr == last_byte_addr )
  108.       {
  109.          l_clip &= r_clip;
  110.  
  111.          outpw ( sequ_addr, l_clip );
  112.  
  113.          *first_byte_addr = (char) color;
  114.       }
  115.       else
  116.       {
  117.          // Draw the first byte.
  118.  
  119.          outpw ( sequ_addr, l_clip );
  120.  
  121.          *first_byte_addr = (char) color;
  122.  
  123.          ++ first_byte_addr;
  124.  
  125.          // Draw the middle bytes.
  126.  
  127.          outpw ( sequ_addr, 0x0F02 );
  128.  
  129.          memset ( first_byte_addr, color, last_byte_addr-first_byte_addr );
  130.  
  131.          // Draw the last byte.
  132.  
  133.          outpw ( sequ_addr, r_clip );
  134.  
  135.          *last_byte_addr = (char) color;
  136.       }
  137.  
  138.       row_addr += bytes_per_row;
  139.    }
  140. }
  141.  
  142. //----------------------------------------------------------------------------
  143. // FUNCTION  vga_t::exists
  144. //----------------------------------------------------------------------------
  145. // Checks to see if there is a VGA display adapter.  Returns true if there
  146. // is, false if there isn't.
  147. //----------------------------------------------------------------------------
  148.  
  149. boolean            vga_t::exists
  150. (
  151.    void
  152. )
  153. {
  154.    boolean         exists;
  155.    union REGS      regs;
  156.  
  157.    regs.h.ah = 0x1A;
  158.    regs.h.al = 0;
  159.  
  160.    int386 ( video_int, & regs, & regs );
  161.  
  162.    if ( regs.h.al == 0x1A )
  163.       exists  =  true;
  164.    else
  165.       exists  =  false;
  166.  
  167.    return  exists;
  168. }
  169.  
  170. //----------------------------------------------------------------------------
  171. // FUNCTION  vga_t::start
  172. //----------------------------------------------------------------------------
  173. // Saves the current video mode and switches to mode 13h.
  174. //----------------------------------------------------------------------------
  175.  
  176. void               vga_t::start ( void )
  177. {
  178.    union REGS      regs;
  179.  
  180.    // Get information about the current video state.
  181.  
  182.    regs.h.ah = 0x0f;
  183.    int386 ( video_int, & regs, & regs );
  184.    old_mode_nr = regs.h.al;
  185.  
  186.    // Start with normal 320x200x256 mode.
  187.  
  188.    regs.x.eax = 0x13;
  189.    int386 ( video_int, & regs, & regs );
  190.  
  191.    // Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4).
  192.  
  193.    outpw ( sequ_addr, 0x0604 );
  194.  
  195.    // Turn off word mode, by setting the Mode Control Register of the
  196.    // CRT Controller (index 0x17, port 0x3d4).
  197.  
  198.    outpw ( crtc_addr, 0xE317 );
  199.  
  200.    // turn off doubleword mode, by setting the Underline Location register
  201.    // (index 0x14, port 0x3d4).
  202.  
  203.    outpw ( crtc_addr, 0x0014 );
  204.  
  205.    // Select all four planes for output.
  206.  
  207.    outpw ( sequ_addr, 0x0F02 );
  208.  
  209.    // Clear display memory to zeroes.
  210.  
  211.    memset ( screen_lin_addr, 0, 0x10000 );
  212. }
  213.  
  214. //----------------------------------------------------------------------------
  215. // FUNCTION  vga_t::end
  216. //----------------------------------------------------------------------------
  217. // Restores the previous video mode.
  218. //----------------------------------------------------------------------------
  219.  
  220. void               vga_t::end
  221. (
  222.    void
  223. )
  224. {
  225.    union REGS      regs;
  226.  
  227.    regs.x.eax = old_mode_nr;
  228.  
  229.    int386 ( video_int, & regs, & regs );
  230. }
  231.  
  232. //----------------------------------------------------------------------------
  233. // FUNCTION  vga_t::clear
  234. //----------------------------------------------------------------------------
  235. // Fills the entire screen buffer with the given color.
  236. //----------------------------------------------------------------------------
  237.  
  238. void               vga_t::clear
  239. (
  240.    int             color
  241. )
  242. {
  243.    // Enable writes to all four planes.
  244.  
  245.    outpw ( sequ_addr, 0x0F02 );
  246.  
  247.    // Clear the active page.
  248.  
  249.    memset ( a_page, color, bytes_per_row * screen_height );
  250. }
  251.  
  252. //----------------------------------------------------------------------------
  253. // FUNCTION  vga_t::update
  254. //----------------------------------------------------------------------------
  255. // Copies the drawing buffer into screen memory.
  256. //----------------------------------------------------------------------------
  257.  
  258. void               vga_t::update
  259. (
  260.    void
  261. )
  262. {
  263.    // Swap the visible and active pages.
  264.  
  265.    {
  266.       int temp    = v_page_nr;
  267.       v_page_nr   = a_page_nr;
  268.       a_page_nr   = temp;
  269.    }
  270.  
  271.    {
  272.       char * temp = v_page;
  273.       v_page = a_page;
  274.       a_page = temp;
  275.    }
  276.  
  277.    // Output the Change Display Offset High byte, along with the high byte of
  278.    // the new display offset.
  279.  
  280.    outpw ( crtc_addr, v_page_nr );
  281.  
  282.    // Now wait for vertical sync, so the active page will be invisible when
  283.    // we start drawing to it.
  284.  
  285. #ifdef VSYNC_MONITOR
  286.    char * p = v_page;
  287.    int counter = 0;
  288.  
  289.    outpw ( sequ_addr, 0x0F02 );
  290. #endif
  291.  
  292.    while ( (inp (input_status_1) & 8) != 0 )
  293.       ;
  294.  
  295.    while ( (inp (input_status_1) & 8) == 0 )
  296.    {
  297.       // Do nothing.
  298.  
  299. #ifdef VSYNC_MONITOR
  300.       ++ counter;
  301.       if ( counter >= 128 )
  302.       {
  303.          counter = 0;
  304.          *p = 255;
  305.          p += bytes_per_row-1;
  306.          *p = 255;
  307.          ++ p;
  308.       }
  309. #endif
  310.    }
  311. }
  312.  
  313. //----------------------------------------------------------------------------
  314. // FUNCTION  win_t::resize
  315. //----------------------------------------------------------------------------
  316. // Resizes the clipping window to the given coordinates.
  317. //----------------------------------------------------------------------------
  318.  
  319. void               win_t::resize
  320. (
  321.    int             new_x1,
  322.    int             new_y1,
  323.    int             new_x2,
  324.    int             new_y2
  325. )
  326. {
  327.    x1 = new_x1;
  328.    y1 = new_y1;
  329.    x2 = new_x2;
  330.    y2 = new_y2;
  331. }
  332.  
  333. //----------------------------------------------------------------------------
  334. // FUNCTION  win_t::clear
  335. //----------------------------------------------------------------------------
  336. // Fills a window with the given color.
  337. //----------------------------------------------------------------------------
  338.  
  339. void               win_t::clear
  340. (
  341.    int             color
  342. )
  343. {
  344.    int             y;
  345.  
  346.    // Scan convert the window.
  347.  
  348.    for ( y = y1; y < y2; ++ y )
  349.    {
  350.       edge_l [y] = x1;
  351.       edge_r [y] = x2-1;
  352.    }
  353.  
  354.    // Fill the window.
  355.  
  356.    draw_scanlines ( y1, y2-1, color );
  357. }
  358.  
  359. //----------------------------------------------------------------------------
  360. // FUNCTION  win_t::point
  361. //----------------------------------------------------------------------------
  362. // Draws a point that is clipped to the given window.
  363. //----------------------------------------------------------------------------
  364.  
  365. void               win_t::point
  366. (
  367.    int             x,
  368.    int             y,
  369.    int             color
  370. )
  371. {
  372.    if ( x >= x1 && x < x2 && y >= y1 && y < y2 )
  373.    {
  374.       outp ( sequ_addr,   0x02 );
  375.       outp ( sequ_addr+1, 0x01 << (x & 3) );
  376.  
  377.       a_page [ bytes_per_row*y + (x / 4) ] = (char) color;
  378.    }
  379. }
  380.  
  381. //----------------------------------------------------------------------------
  382. // FUNCTION  win_t::rect
  383. //----------------------------------------------------------------------------
  384. // Draws a filled rectangle that is clipped to the given window.
  385. //----------------------------------------------------------------------------
  386.  
  387. void               win_t::rect
  388. (
  389.    int             rect_x1,
  390.    int             rect_y1,
  391.    int             rect_x2,
  392.    int             rect_y2,
  393.    int             color
  394. )
  395. {
  396.    int             y;
  397.  
  398.    // Clip the rectangle to the viewing window.
  399.  
  400.    if ( rect_x2 < x1 || rect_x1 >= x2 ||
  401.         rect_y2 < y1 || rect_y1 >= y2 )
  402.       goto  exit_func;
  403.  
  404.    if ( rect_x1 < x1 )
  405.       rect_x1 = x1;
  406.  
  407.    if ( rect_x2 > x2 )
  408.       rect_x2 = x2;
  409.  
  410.    if ( rect_y1 < y1 )
  411.       rect_y1 = y1;
  412.  
  413.    if ( rect_y2 > y2 )
  414.       rect_y2 = y2;
  415.  
  416.    // Scan convert the rectangle.
  417.  
  418.    rect_x2 -= 1;
  419.    rect_y2 -= 1;
  420.  
  421.    for ( y = rect_y1; y <= rect_y2; ++ y )
  422.    {
  423.       edge_l [y] = rect_x1;
  424.       edge_r [y] = rect_x2;
  425.    }
  426.  
  427.    // Draw!
  428.  
  429.    draw_scanlines ( rect_y1, rect_y2, color );
  430.  
  431. exit_func:
  432.  
  433.    return;
  434. }
  435.  
  436. //----------------------------------------------------------------------------
  437. // FUNCTION  win_t::line
  438. //----------------------------------------------------------------------------
  439. // Draws a line that is clipped to the given window.
  440. //----------------------------------------------------------------------------
  441.  
  442. void               win_t::line
  443. (
  444.    int             line_x1,
  445.    int             line_y1,
  446.    int             line_x2,
  447.    int             line_y2,
  448.    int             color
  449. )
  450. {
  451.    int             delta_x;
  452.    int             delta_y;
  453.  
  454.    // Switch the points so that (line_x1,line_y1) is always the top one.
  455.  
  456.    if ( line_y2 < line_y1 )
  457.    {
  458.       swap ( line_x1, line_x2 );
  459.       swap ( line_y1, line_y2 );
  460.    }
  461.  
  462.    // Compute the x and y deltas.
  463.  
  464.    delta_x  =  line_x2 - line_x1;
  465.    delta_y  =  line_y2 - line_y1;
  466.  
  467.    // Clip the line on the left and right edges.
  468.  
  469.    if ( line_x1 < x1 )
  470.    {
  471.       if ( line_x2 < x1 )  goto  exit_func;
  472.  
  473.       line_y1 += ( delta_y * ( x1 - line_x1 ) / delta_x );
  474.       line_x1  = x1;
  475.    }
  476.    else if ( line_x1 >= x2 )
  477.    {
  478.       if ( line_x2 >= x2 )  goto  exit_func;
  479.  
  480.       line_y1 += ( delta_y * ( x2 - line_x1 ) / delta_x );
  481.       line_x1  = x2 - 1;
  482.    }
  483.  
  484.    if ( line_x2 < x1 )
  485.    {
  486.       line_y2 += ( delta_y * ( x1 - line_x2 ) / delta_x );
  487.       line_x2  = x1;
  488.    }
  489.    else if ( line_x2 >= x2 )
  490.    {
  491.       line_y2 += ( delta_y * ( x2 - line_x2 ) / delta_x );
  492.       line_x2  = x2 - 1;
  493.    }
  494.  
  495.    // Don't draw lines that are completely off the screen.
  496.  
  497.    if ( line_y2 < y1 || line_y1 >= y2 )  goto  exit_func;
  498.  
  499.    // Clip the line on the top edge.
  500.  
  501.    if ( line_y1 < y1 )
  502.    {
  503.       line_x1 += ( delta_x * ( y1 - line_y1 ) / delta_y );
  504.       line_y1  = y1;
  505.  
  506.       if ( line_x1 <  x1 )  line_x1 = x1;
  507.       if ( line_x1 >= x2 )  line_x1 = x2 - 1;
  508.    }
  509.  
  510.    // Clip the line on the bottom edge.
  511.  
  512.    if ( line_y2 >= y2 )
  513.    {
  514.       line_x2 += ( delta_x * ( y2 - line_y2 ) / delta_y );
  515.       line_y2  = y2 - 1;
  516.  
  517.       if ( line_x2 <  x1 )  line_x2 = x1;
  518.       if ( line_x2 >= x2 )  line_x2 = x2 - 1;
  519.    }
  520.  
  521.    // Recompute the x and y deltas using the clipped coordinates.
  522.  
  523.    delta_x  =  line_x2 - line_x1;
  524.    delta_y  =  line_y2 - line_y1;
  525.  
  526.    // Draw the line.
  527.  
  528.    {
  529.       int          denominator;
  530.       int          nr_pixels;
  531.       int          frac_x;
  532.       int          frac_y;
  533.       int          add_x;
  534.       const int    add_y = 1;
  535.  
  536.  
  537.       if (delta_x > 0)
  538.       {
  539.          add_x   = 1;
  540.       }
  541.       else
  542.       {
  543.          add_x   = -1;
  544.          delta_x = -delta_x;
  545.       }
  546.  
  547.       if ( delta_y > delta_x )
  548.       {
  549.          denominator = delta_y;
  550.          nr_pixels   = delta_y + 1;
  551.       }
  552.       else
  553.       {
  554.          denominator = delta_x;
  555.          nr_pixels   = delta_x + 1;
  556.       }
  557.  
  558.       frac_y = frac_x = denominator >> 1;
  559.  
  560.       for ( ; nr_pixels > 0; -- nr_pixels )
  561.       {
  562.          point ( line_x1, line_y1, color );
  563.  
  564.          frac_x += delta_x;
  565.  
  566.          if ( frac_x > denominator )
  567.          {
  568.             frac_x     -= denominator;
  569.             line_x1    += add_x;
  570.          }
  571.  
  572.          frac_y += delta_y;
  573.  
  574.          if ( frac_y > denominator )
  575.          {
  576.             frac_y     -= denominator;
  577.             line_y1    += add_y;
  578.          }
  579.       }
  580.    }
  581.  
  582. exit_func:
  583.  
  584.    return;
  585. }
  586.  
  587.